import backtrader as bt

import akshare as ak
import pandas as pd
import sqlite3
from datetime import datetime, timedelta
import backtrader as bt

from sqlitetool import sqlite3_tool as st
import SQLiteDataFeed as sdf

"""
使用移动平均线交叉和标准差判断大盘趋势及市场阶段：
下面的代码通过计算大盘指数（以沪深 300 为例，可根据实际情况替换数据源）的短期和长期移动平均线，并结合价格波动的标准差来判断大盘趋势以及所处阶段。
当短期移动平均线上穿长期移动平均线且价格波动相对较小时，认为处于牛市；
当短期移动平均线下穿长期移动平均线且价格波动相对较小时，认为处于熊市；
当价格波动较大且移动平均线交叉频繁时，认为处于震荡市。
"""


def get_hs300etf_data():
    # 获取当前日期
    today = datetime.now()
    # 计算一年前的日期
    one_year_ago = today - timedelta(days=365)

    # 获取沪深300ETF日线数据
    hs300etf_df = ak.fund_etf_hist_em(
        symbol="510300",
        period="daily",
        start_date=one_year_ago.strftime("%Y%m%d"),
        end_date=today.strftime("%Y%m%d"),
    )

    # 数据处理，确保日期格式正确
    hs300etf_df["日期"] = pd.to_datetime(hs300etf_df["日期"])
    hs300etf_df["code"] = "510300"
    hs300etf_df["name"] = "沪深300ETF"
    # 日期     开盘     收盘     最高     最低       成交量           成交额    振幅   涨跌幅    涨跌额   换手率
    hs300etf_df.rename(
        columns={
            "日期": "trade_date",
            "开盘": "open_price",
            "收盘": "close_price",
            "最高": "high_price",
            "最低": "low_price",
            "成交量": "volume",
            "成交额": "amount",
        },
        inplace=True,
    )
    print(hs300etf_df.head())
    print("get_hs300etf_data")
    return hs300etf_df


def get_db_tool():
    # 连接到SQLite数据库（如果不存在则创建）
    db_tool = st.SQLiteTool("financial_data.db")
    return db_tool


def get_sh000300_data():
    db_tool = get_db_tool()
    table_name = "hs300etf_daily"

    df2 = db_tool.select_list_to_dataframe(
        table_name,
        columns="trade_date, open_price, close_price, high_price, low_price, volume, amount",
        condition=None,
        order_by="id asc",
        limit="1000",
    )
    df2.rename(
        columns={
            "trade_date": "date",
            "open_price": "open",
            "close_price": "close",
            "high_price": "high",
            "low_price": "low",
            "volume": "volume",
            "amount": "amount",
        },
        inplace=True,
    )
    df2["date"] = pd.to_datetime(df2["date"])
    # datetime.strftime(df2["trade_date"], "%Y-%m-%d")
    print(df2)
    return df2


class MarketTrendStrategy(bt.Strategy):
    params = (
        ("short_window", 50),
        ("long_window", 200),
        ("volatility_threshold", 0.01),
    )

    def __init__(self):
        self.short_ma = bt.indicators.SimpleMovingAverage(
            self.data.close, period=self.p.short_window
        )
        self.long_ma = bt.indicators.SimpleMovingAverage(
            self.data.close, period=self.p.long_window
        )
        self.volatility = bt.indicators.StandardDeviation(self.data.close, period=20)

    def next(self):
        if (
            self.short_ma[0] > self.long_ma[0]
            and self.volatility[0] < self.p.volatility_threshold
        ):
            print(f"{self.data.datetime.date(0)} 处于牛市阶段")
        elif (
            self.short_ma[0] < self.long_ma[0]
            and self.volatility[0] < self.p.volatility_threshold
        ):
            print(f"{self.data.datetime.date(0)} 处于熊市阶段")
        else:
            print(f"{self.data.datetime.date(0)} 处于震荡市阶段")


# 示例使用
# cerebro = bt.Cerebro()
# # 这里以沪深 300 指数数据为例，实际应用中需根据数据源调整
# data = bt.feeds.PandasData(dataname=get_hs300etf_data())
# cerebro.adddata(data)
# cerebro.addstrategy(MarketTrendStrategy)
# cerebro.run()


if __name__ == "__main__":
    print("main")
    # Create a cerebro entity
    cerebro = bt.Cerebro()

    # Add a strategy
    cerebro.addstrategy(MarketTrendStrategy)

    # data = bt.feeds.PandasData(dataname=get_sh000300_data())
    data_base_name = "financial_data.db"
    table_name = "hs300etf_daily"
    sql = f"select trade_date, open_price, close_price, high_price, low_price, volume, amount from {table_name}"
  
    data = sdf.SQLiteDataFeed(data_base_name,sql)

    # Add the Data Feed to Cerebro
    cerebro.adddata(data)

    # Set our desired cash start
    cerebro.broker.setcash(1000.0)

    # Add a FixedSize sizer according to the stake
    cerebro.addsizer(bt.sizers.FixedSize, stake=10)

    # Set the commission
    cerebro.broker.setcommission(commission=0.0)

    # Print out the starting conditions
    print("Starting Portfolio Value: %.2f" % cerebro.broker.getvalue())

    # Run over everything
    cerebro.run()

    # Print out the final result
    print("Final Portfolio Value: %.2f" % cerebro.broker.getvalue())

    # Plot the result
    cerebro.plot(style="candle", barup="red", bardown="green")


"""
代码说明：
参数定义：
short_window：短期移动平均线的周期，这里设置为 50 天。
long_window：长期移动平均线的周期，设置为 200 天。
volatility_threshold：用于判断市场波动程度的标准差阈值，设置为 0.01。
指标计算：
short_ma：计算短期简单移动平均线。
long_ma：计算长期简单移动平均线。
volatility：计算过去 20 天收盘价的标准差，用于衡量价格波动程度。
趋势判断：
在 next 方法中，通过比较短期和长期移动平均线的位置关系，并结合标准差与阈值的比较，来判断市场处于牛市、熊市还是震荡市。
数据获取：
get_sh000300_data 函数应实现获取沪深 300 指数数据的功能，目前示例返回空的 DataFrame，实际应用中需根据数据源（如网络 API、本地数据库等）进行数据获取逻辑的编写。
"""
